﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.XPath;
using System.Linq;
using SocialFront.Entities;
using SocialFront.Providers.Blog;
using SocialFront.Providers.Comment;
using SocialFront.Providers.Member;
using umbraco.cms.businesslogic.relation;
using umbraco.cms.businesslogic.web;
using umbraco.presentation.nodeFactory;
using umbraco.editorControls;
using apiBll = umbraco.BusinessLogic;
using apiRelation = umbraco.cms.businesslogic.relation;

namespace SocialFront.Provider.Umbraco
{
    public class UmbracoBlog : BlogBase
    {
        public override Blog CreateBlog(Blog blog)
        {
            apiRelation.Relation[] relations = apiRelation.Relation.GetRelations(blog.Member.Id,
                                                                                 RelationType.GetByAlias(
                                                                                     "relateMemberToBlogDocType"));
            if (relations.Length > 1)
            {
                throw new Exception("Too many relateMemberToBlogDocType relationships in database for user " +
                                    blog.Member.LoginName);
            }
            Document newDocument = Document.MakeNew(
                blog.Title,
                DocumentType.GetByAlias("sfBlogEntry"),
                apiBll.User.GetUser(0),
                relations[0].Child.Id);

            newDocument.getProperty("title").Value = blog.Title;
            newDocument.getProperty("pageTitle").Value = blog.Title;
            newDocument.getProperty("content").Value = blog.Content;
            if (Config.sfPublishBlogOnSave)
                newDocument.getProperty("enabled").Value = true;
            else
                newDocument.getProperty("enabled").Value = false;
            TagProvider.Provider.AddTags(blog.Tags, newDocument.Id);
            newDocument.Save();
            newDocument.Publish(new apiBll.User(0));
            umbraco.library.UpdateDocumentCache(newDocument.Id);
            blog.Id = newDocument.Id;
            blog.Url = umbraco.library.NiceUrl(blog.Id);
            RelationType relationTypeM2Dt = RelationType.GetByAlias("relateMemberToDocType");
            Member member = MemberProvider.Provider.GetCurrentMember();
            apiRelation.Relation.MakeNew(member.Id, newDocument.Id, relationTypeM2Dt,
                                         member.LoginName + " to " + newDocument.getProperty("title"));

            return blog;
        }

        public override Blog UpdateBlog(Blog blog)
        {
            throw new NotImplementedException();
        }

        public override void DeleteBlog(int id)
        {
            Document document = new Document(id);
            document.delete();
        }

        public override void DeleteBlog(Blog blog)
        {
            DeleteBlog(blog.Id);
        }

        public override Blog GetBlogById(int id)
        {
            Node node = new Node(id);
            return ConvertNodeToBlog(node);
        }

        public override XPathNodeIterator GetBlogXmlById(int id)
        {
            return umbraco.library.GetXmlNodeById(id.ToString());
        }

        public override List<Blog> GetAllBlogs()
        {
            return GetAllBlogs(i => i.CreatedDate);
        }

        public override List<Blog> GetAllBlogs<T>(Func<Blog, T> sortField)
        {
            return GetAllBlogs(null, sortField);
        }

        public override List<Blog> GetAllBlogs<T>(int? pageSize, Func<Blog, T> sortField)
        {
            return GetAllBlogs(pageSize, null, sortField);
        }

        public override List<Blog> GetAllBlogs<T>(int? pageSize, int? page, Func<Blog, T> sortField)
        {
            int total;
            return GetAllBlogs(pageSize, page, out total, sortField);
        }

        public override List<Blog> GetAllBlogs<T>(int? pageSize, int? page, out int total, Func<Blog, T> sortField)
        {
            Node node = new Node(-1);
            List<Node> nodes = NodeHelper.GetNodesByAliasType(node, "sfBlogEntry");
            List<Blog> blogs = ConvertNodesToBlogs(nodes);
            blogs = blogs.Where(b => b.Enabled).ToList();
            if (pageSize.HasValue && page.HasValue)
                blogs = blogs.OrderByDescending(sortField).Skip((page.Value - 1) * pageSize.Value).Take(pageSize.Value).ToList();
            else if (pageSize.HasValue)
                blogs = blogs.OrderByDescending(sortField).Take(pageSize.Value).ToList();
            else
                blogs = blogs.OrderByDescending(sortField).ToList();

            total = blogs.Count;
            return blogs;
        }

        private static Blog ConvertNodeToBlog(Node node)
        {
            Blog blog = new Blog();
            blog.ModifiedDate = node.UpdateDate;
            blog.CreatedDate = node.CreateDate;
            blog.Id = node.Id;
            blog.Title = node.GetProperty("title").Value;
            blog.Content = node.GetProperty("content").Value;
            blog.Tags = TagProvider.Provider.GetTags(node.Id);
            blog.PageUrl = umbraco.library.NiceUrl(node.Id);
            if (node.GetProperty("enabled").Value != "")
                blog.Enabled = Convert.ToBoolean(Convert.
                                                     ToInt32(node.GetProperty("enabled").Value));
            else
                blog.Enabled = false;
            blog.Url = umbraco.library.NiceUrl(node.Id);

            apiRelation.Relation[] relations = apiRelation.Relation.GetRelations(node.Id, apiRelation.RelationType.GetByAlias("relateMemberToDocType"));
            if (relations.Length != 1)
            {
                relations = apiRelation.Relation.GetRelations(node.Parent.Id,
                                                              apiRelation.RelationType.GetByAlias(
                                                                  "relateMemberToBlogDocType"));
            }
            Member member = MemberProvider.Provider.GetMemberById(relations[0].Parent.Id);
            blog.Member = member;

            return blog;
        }

        private static List<Blog> ConvertNodesToBlogs(List<Node> nodes)
        {
            List<Blog> blogs = new List<Blog>();
            foreach (Node node in nodes)
            {
                blogs.Add(ConvertNodeToBlog(node));
            }
            return blogs;
        }

        public override List<Blog> GetBlogsByMember(int id)
        {
            return GetBlogsByMember(id, 0, null);
        }

        public override List<Blog> GetBlogsByMember(Member member)
        {
            return GetBlogsByMember(member.Id);
        }

        public override List<Blog> GetBlogsByMember(int id, int page, int? pageSize)
        {
            apiRelation.Relation[] relation = apiRelation.Relation.GetRelations(id, RelationType.GetByAlias("relateMemberToBlogDocType"));
            if (relation.Count() != 0)
            {
                Node node = new Node(relation[0].Child.Id);
                List<Node> nodes = NodeHelper.GetNodesByAliasType(node, "sfBlogEntry", pageSize);
                List<Blog> blogs = ConvertNodesToBlogs(nodes);
                blogs = blogs.Where(b => b.Member.Id == id).ToList();
                return blogs.Where(b => b.Enabled = true).ToList();
            }
            return null;
        }

        public override List<Blog> GetBlogsByMember(Member member, int page, int? pageSize)
        {
            return GetBlogsByMember(member.Id, page, pageSize);
        }

        public override List<Blog> GetBlogsByMember(int id, int page, int? pageSize, out int total)
        {
            throw new NotImplementedException();
        }

        public override List<Blog> GetBlogsByMember(Member member, int page, int? pageSize, out int total)
        {
            throw new NotImplementedException();
        }

        public override string GetMemberBlogUrl(Member member)
        {
            apiRelation.Relation[] relation = apiRelation.Relation.GetRelations(member.Id, RelationType.GetByAlias("relateMemberToBlogDocType"));
            if (relation.Count() != 0)
            {
                return umbraco.library.NiceUrl(relation[0].Child.Id);
            }
            return null;
        }

        public override string GetMemberBlogUrl(int memberId)
        {
            return GetMemberBlogUrl(MemberProvider.Provider.GetMemberById(memberId));
        }
    }
}